//Version 15 - Parte A y B:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <fcntl.h>
#define STDIN_FID 0
#define STDOUT_FID 1

int parsing(char line[], char* args[], char type1[], char type2[]);
void command(char* args[], char* path);
void seek(char *arreglo[]);
void changeDir(char* args[], char* path);
void showPrompt();
int whichstatus(int cantArgs,char* args[]);
void redirection(char* file_name);

char* directories[100];
char* PATH;
int flagstatus;
int position;

int main(int argc, char *argv[]){
    printf("--------------------------BAASH--------------------------\n");
    char* args[100];   
    char line[1024];
    int cantarg;
    
    PATH = getenv("PATH");
    parsing(PATH, directories, ":",":");
        
    while(1){  
        
        flagstatus=0;
        showPrompt();                  
        
        if (fgets(line, 1024, stdin) == NULL) return 0;     //Exit
                else{
                        cantarg=parsing(line, args, " ", " \n");    //Parsea la linea de entrada.
                        position=whichstatus(cantarg,args);
                        command(args, getcwd(NULL, 0));     //sino, interpreta el comando (agrs[0])
                        }
                

    }
    return 0;
}

int whichstatus(int cantArgs,char* args[]){
        int i;
        for (i=0;i<cantArgs;i++){
                if(strcmp(args[i],"&")==0){
                        args[i] = NULL;
                        cantArgs--;
                        flagstatus=1;
                        return i;
                }
                if(strcmp(args[i],"<")==0){
                        args[i] = NULL;
                        cantArgs--;
                        flagstatus=2;
                        return i;
                }
                if(strcmp(args[i],">")==0){
                        args[i] = NULL;
                        cantArgs--;
                        flagstatus=3;
                        return i;
                }
                if(strcmp(args[i],"|")==0){
                        args[i] = NULL;
                        cantArgs--;
                        flagstatus=4;
                        return i;
                }
        }return i;
}

//Muestra el prompt
void showPrompt(){
    printf("%s # %s > ", getenv("LOGNAME"),(char*) getcwd(NULL, 0));            
}

//Parsea una linea
int parsing(char line[], char* args[], char type1[], char type2[]){ 
    int i = 0;
    args[i] = strtok(line, type1);    
    while((args [i]) != NULL) {
                i++;
        args[i] = strtok (NULL, type2);
    }
    return i;
}

//Interpreta el comando: si es cd llama a changedir(), si no es cd llama a seek().
void command(char* args[], char* path){
    if(strcmp(args[0], "exit\n") == 0) exit(1);
    if(strcmp(args[0], "\n") == 0) return;
    if(strcmp(args[0], "cd") == 0) changeDir(args, path);
        else seek(args);
}

//Cambia el directorio (comando cd)
void changeDir(char* args[], char* path){
    if( chdir(args[1]) != 0 ) perror("Command not found\n");
        else path = (char*) getcwd(NULL, 0);
}

//Busqueda de secuencia PATH, caminos abusolutos y relativos 
void seek(char *args[]){
    char str[200];
    int flag = 0;
    int num = 0;
    pid_t pid;

    //En cada uno de los PATH debo probar si esta el comando 
    
    if ( (pid = fork()) == 0){  // HIJO ---------------------------------------------------------------------------------------
                
                if(flagstatus==2||flagstatus==3){
                        redirection(args[position+1]);
                        args[position+1]=NULL;
                        }
                if(args[0][0]=='.'){          //Si comienza con un ./ o   ../
                        char * aux1;
            char * aux2;
            int status = 0;
    
            aux1 = strtok(args[0],"/");     
            aux2 = aux1;
    
            while((status == 0)&&((aux1 = strtok(NULL,"/"))!= NULL)){
                                status = chdir(aux2);   
                aux2 = aux1;            
                        }                                       
    
            char* path = (char*) getcwd(NULL, 0);   //Encuentra el pwd.
            strcat (path,"/");
            strcat (path,aux2);     
            strncpy(str,path,sizeof(str));
    
                        //Quita el final de linea, solo si no habia & (ya que si habia, fue quitado):
                        if (flagstatus==0){              
                                int j=0;
                                int n=0;
                                while(str[j]!='\0')j++;                
                for(n=0;n<j;n++) if((str[n]=='\n')||(str[n]=='\0'))str[n]='\0';
                        }
                        
                        if((access(str,F_OK))==0){
                                execv(str, args);
                                exit(1);
                        }
                        else{
                                perror("Error, File not found \n");
                                exit(1);
                        }
                }
                else{   
                        //Si no comienza con un ./ o / 
            int i = 0;        
            char* dir[100];
                
            while( directories[i] != NULL ){                    
                                //Busca en PATH el comando especificado:    
                //Arma el string = path + / + comando:    
                dir[i] = directories[i];
                strcpy (str, dir[i]);                            
                strcat (str, "/");
                strcat(str, args[0]);

                                //Quita el final de linea, solo si no habia & (ya que si habia, fue quitado):
                if (flagstatus==0){
                                        int j = 0;
                    while(str[j]!='\0')j++;                
                    if ( args[1] != NULL ) str[j] = '\0';
                    else str[j-1] = '\0';
                                }
                //Si lo encuentra lo ejecuta:
                
                if( (access(str,F_OK)) == 0 ){
                execv(str, args);
                num = 1;
                }
                                else i++;       //Si no lo encientra incrementa i, para buscar en otro directorio.
                        }
             
             //Si no encontro el comando en todo PATH muestra un mensaje de error:
             if( num == 0 ){
                                perror("File not found");
                exit(1);
                        }
        }            
        }
        else if ( pid>0 )flag =-1; // PADRE ---------------------------------------------------------------------------------------
                
    if(flagstatus!=1){                                          //Si no habia &, espera al hijo
                waitpid(pid, &flag, 0);         
        args=NULL;                      
        }
        else {                                                  //Si habia &, no lo espera
                args = NULL;
        waitpid(pid, &flag, WNOHANG);
        }
        
}

//Redireccion de I/O
void redirection(char* file_name){
        int fid;

        if(flagstatus ==2){
                fid = open(file_name, O_RDONLY, S_IWUSR|S_IRUSR);
                if(fid<0) perror("open");
                close(STDIN_FID);
                if(dup(fid)<0)perror("dup");
        }

        if(flagstatus ==3){
                fid = open(file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IWUSR|S_IRUSR);
                if(fid<0) perror("open");
                close(STDOUT_FID);
                if(dup(fid)<0)perror("dup");
        }
}       
